package elephant.servers.consoleserver.termos;

import static java.util.Collections.emptyList;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import elephant.servers.consoleserver.command.SshdCommand;

/**
 * @author <a href="mailto:trygvis@java.no">Trygve Laugst&oslash;l</a>
 * @version $Id$
 */
public class Repl {
	//
	private static final Logger logger=LoggerFactory.getLogger(Repl.class);
	//
    public static void repl(InputStream stdin, OutputStream stdout, OutputStream stderr,
                           ReadLineEnvironment environment,
                           Map<String, SshdCommand> commands, String prompt)
        throws IOException {
        String line;
        while (true) {
            ReadLine readLine = new ReadLine(stdin, stdout, environment);
            line = readLine.readLine(prompt, new CommandCompleter(commands));
            if (line == null) {
                break;
            }
            line = line.trim();
            if ("".equals(line)) {
                continue;
            }
            if((ReadLine.ETX+"").equals(line)){//control+c
            	commands.values().forEach(cmd->cmd.onControlC());
            	continue;
            }
            //Make this customizable, have a callback to be called so that the one starting the Repl
            // can determine if we should stop or not.
            if ("exit".equals(line)) {
                readLine.flush();
                break;
            }
            //add history command
            environment.addHistoryCommand(line);
            //
            if("help".equals(line)){
            	readLine.println("all command list:");
        		String format="%-20s: %-20s\r";
        		for(SshdCommand cmd:commands.values()){
        			readLine.println(String.format(format,cmd.name,cmd.desc));
        		}
        		continue;
            }
            String[] args = line.split(" ");
            SshdCommand command = commands.get(args[0]);
            if (command == null) {
                readLine.println("Unknown command '" + line + "'.");
                continue;
            }
            //
            String[] realArgs = new String[args.length - 1];
            System.arraycopy(args, 1, realArgs, 0, realArgs.length);
            try {
                command.run(stdin,
                    new TerminalOutputStream(stdout, environment.ocrnl),
                    new TerminalOutputStream(stderr, environment.ocrnl),
                    environment,
                    realArgs);
            } catch (Exception e) {
            	logger.error(e.getMessage(),e);
            }
        }
    }

    public static class CommandCompleter implements Completer {
        private final Map<String, SshdCommand> commands;

        CommandCompleter(Map<String, SshdCommand> commands) {
            this.commands = commands;
        }
        //
        public List<String> complete(String string, int position) {
            int index = string.indexOf(' ');
            if (index == -1 || index > position) {
                return completeStrings(commands.keySet(), string);
            } else {
                return completeCommand(string, index);
            }
        }
        //
        public static List<String> completeStrings(Collection<String> strings, String string) {
            List<String> matches = new ArrayList<String>();

            for (String s : strings) {
                if (s.startsWith(string)) {
                    matches.add(s);
                }
            }
            return matches;
        }
        //
        private List<String> completeCommand(String string, int index) {
            String commandName = string.substring(0, index).trim();
            SshdCommand command = commands.get(commandName);
            if (command == null) {
                return emptyList();
            }
            //
            if (!(command instanceof Completer)) {
                return emptyList();
            }
            Completer completer = (Completer) command;
            return completer.complete(string.substring(index + 1), 0);
        }
    }
}
